#pragma once

#include<iostream>
#include<unistd.h>
#include<memory>
#include<string.h>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include<cstdlib>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<signal.h>
#include<pthread.h>
#include"Log.hpp"
#include"ThreadPool.hpp"
#include"Task.hpp"


using namespace std;

const int defaultfd = -1;
const string defaultip = "0.0.0.0";
const int backlog = 5;
extern Log lg;

enum
{
    UsageError = 1,
    SocketError,
    BindError,
    ListenError
};

class TcpServer
{

};

class ThreadData
{
public:
    ThreadData(int fd,const string &ip, uint16_t port, TcpServer *t)
    :sockfd(fd)
    ,clientip(ip)
    ,clientport(port)
    ,tsvr(t)
    {}
public:
    int sockfd;
    string clientip;
    uint16_t clientport;
    TcpServer *tsvr;
};

class TcpServer
{
public:
    TcpServer(const uint16_t &port, const string &ip = defaultip)
    :_listen_sockfd(defaultfd)
    ,_serverip(ip)
    ,_serverport(port)
    {}

    void Init()
    {
        _listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_listen_sockfd < 0)
        {
            lg(Fatal, "error: %d", errno);
            exit(SocketError);
        }
        lg(Info, "create _listen_sockfd success, sockfd : %d", _listen_sockfd);

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_serverport);
        inet_aton(_serverip.c_str(), &local.sin_addr);

        int ret = bind(_listen_sockfd, (struct sockaddr*)&local, sizeof(local));
        if(ret < 0)
        {
            lg(Fatal, "bind error, errno : %d", errno);
            exit(BindError);
        }
        lg(Info, "bind _listen_sockfd success, sockfd : %d", _listen_sockfd);

        if(listen(_listen_sockfd, backlog) < 0)
        {
            lg(Fatal, "listen error, errno : %d", errno);
            exit(ListenError);
        }
        lg(Info, "listen _listen_sockfd success, sockfd : %d", _listen_sockfd);
    }

    // static void *Routine(void *args)
    // {
    //     pthread_detach(pthread_self());
    //     ThreadData* td =static_cast<ThreadData*>(args);
    //     td->tsvr->Service(td->sockfd, td->clientip, td->clientport);
    //     delete td;
    //     return nullptr;
    // }
    void Start()
    {
        ThreadPool<Task>::GetInstance()->Start();
        // signal(SIGCHLD, SIG_IGN); 第二个方式
        lg(Info, "server is running...");
        for(;;)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(_listen_sockfd, (struct sockaddr*)&client, &len);
            if(sockfd < 0)
            {
                lg(Waring, "accept error, errno : %d\n", errno);
                continue;
            }
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(client.sin_addr), clientip, sizeof(clientip));

            lg(Info, "get a new link..., sockfd:%d, client ip:%s, client port:%d\n", sockfd, clientip, clientport);
            //单进程版
            // Service(sockfd, clientip, clientport);
            // close(sockfd);
            
            //多进程版
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     close(_listen_sockfd);
            //     if(fork() > 0) exit(0);
            //     Service(sockfd, clientip, clientport);//孙子进程 system领养
            //     close(sockfd);
            //     exit(0);
            // }
            // close(sockfd);
            // pid_t rid = waitpid(id, nullptr, 0);

            //多线程版
            // ThreadData *td = new ThreadData(sockfd, clientip, clientport, this);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, Routine, td);

            //线程池版
            Task t(sockfd, clientip, clientport);
            ThreadPool<Task>::GetInstance()->Push(t);
        }
    }

    // void Service(int sockfd, const string &clientip, uint16_t clientport)
    // {
    //     char buffer[4096];
    //     while(true)
    //     {
    //         ssize_t n = read(sockfd, buffer, sizeof(buffer));
    //         if(n < 0)
    //         {
    //             lg(Waring, "read failed, errno: %d", errno);
    //             break;
    //         }
    //         else if(n == 0)
    //         {
    //             lg(Info, "%s:%d quit, server close sockfd: %d", clientip.c_str(), clientport, sockfd);
    //             break;
    //         }
    //         buffer[n] = 0;
    //         cout<<"client say#"<<buffer<<endl;
    //         string echo_string = "tcpserver echo#";
    //         echo_string += buffer;

    //         write(sockfd, echo_string.c_str(), echo_string.size());
    //     }
    // }

    ~TcpServer()
    {}
private:
    int _listen_sockfd;
    string _serverip;
    uint16_t _serverport;
};